package com.boss.fileapp.util;

import com.boss.framework.exception.AppRuntimeException;
import org.apache.tools.zip.ZipEntry;
import org.apache.tools.zip.ZipOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

/**
 * <br>Title:
 * <br>Description:
 * <br>Author:
 * <br>Date:
 */
public class ZipUtils {

    /**
     * 日志
     */
    private static Logger logger = LoggerFactory.getLogger(ZipUtils.class);

    /** 压缩文件格式 **/
    private static final String FORMAT = "zip";
    /** 要压缩的文件后缀 **/
    private static final String FILE_SUFFIX = ".txt";

    /**
     * 生成压缩文件主方法
     * @param path   要压缩的文件路径
     * @param fileNames 要压缩的文件名集合
     * @param compressName 压缩后文件名
     */
    public static void generateCompressFile(String path, List<String> fileNames, String compressName) {
        // 判断要压缩的文件名集合是否为空
        if (StringUtils.isEmpty(fileNames) || fileNames.size() <= 0) {
            throw new AppRuntimeException("要压缩的文件集合 fileNames 为空！");
        }
        FileOutputStream outputStream = null;
        ZipOutputStream zipOutputStream = null;
        try {
            File file = new File(path);
            // 压缩文件的路径不存在
            if (!file.exists()) {
                throw new AppRuntimeException("路径 " + path + " 不存在文件，无法进行压缩...");
            }
            // 用于存放压缩文件的文件夹
            // 当前是放到和要压缩的文件在一个文件夹内
            String generateFile = path;
            File compress = new File(generateFile);
            // 如果文件夹不存在，进行创建
            if( !compress.exists() ){
                compress.mkdirs();
            }
            // 目的压缩文件
            String generateFileName = path + File.separator + compressName + "." + FORMAT;
            // 输出流
            outputStream = new FileOutputStream(generateFileName);
            // 压缩输出流
            zipOutputStream = new ZipOutputStream(new BufferedOutputStream(outputStream));
            // 生成压缩文件
            generateFile(zipOutputStream,file,"", fileNames);
            logger.info("源文件位置：" + file.getAbsolutePath() + "，目的压缩文件生成位置：" + generateFileName);
        } catch (Exception e) {
            throw new AppRuntimeException(e.getMessage());
        } finally {
            // 关闭流
            if (zipOutputStream != null) {
                try {
                    zipOutputStream.close();
                } catch (IOException e) {
                    throw new AppRuntimeException(e.getMessage());
                }
            }
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    throw new AppRuntimeException(e.getMessage());
                }
            }
        }
    }

    /**
     * @param out  输出流
     * @param file 目标文件
     * @param dir  文件夹
     * @param fileNames 要压缩的文件数组集合
     * @throws Exception
     */
    private static void generateFile(ZipOutputStream out, File file, String dir, List<String> fileNames) {
        FileInputStream inputStream = null;
        // 当前的是文件夹，则进行一步处理
        if (file.isDirectory()) {
            //得到文件列表信息
            File[] files = file.listFiles();
            //循环将文件夹中的文件打包
            for (int i = 0; i < files.length; i++) {
                // 压缩指定文件
                if (fileNames.contains(files[i].getName())) {
                    generateFile(out, files[i], files[i].getName(), fileNames);
                }
            }
        } else { // 当前是文件
            // 输入流
            try {
                inputStream = new FileInputStream(file);
                // 标记要打包的条目
                out.putNextEntry(new ZipEntry(dir));
                // 进行写操作
                int len = 0;
                byte[] bytes = new byte[1024];
                while ((len = inputStream.read(bytes)) > 0) {
                    out.write(bytes, 0, len);
                }
            } catch (IOException e) {
                throw new AppRuntimeException(e.getMessage());
            } finally {
                // 关闭流
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    } catch (IOException e) {
                        throw new AppRuntimeException(e.getMessage());
                    }
                }
            }
        }
    }

    // 测试
    public static void main(String[] args) {
        String path = "E:\\zip";
        String filename = "eee";
        List<String> files = new ArrayList<>();
        files.add("1.txt");
//        files.add("2.txt");
//        files.add("6.txt");
        try {
            generateCompressFile(path, files, filename);
        } catch (Exception e) {
            e.printStackTrace();
            logger.info(e.getMessage());
        }

    }
}
